﻿using System;
using System.Collections.Specialized;
using System.Linq;

using Xamarin.Forms;
using Xamarin.Forms.Platform.WinPhone;

using Size = Xamarin.Forms.Size;

//[assembly: ExportRenderer(typeof(Outcoder.UI.Xaml.AppBar), typeof(Outcoder.UI.Xaml.Renderers.AppBarRenderer))]

namespace Outcoder.UI.Xaml.Renderers
{
	public class AppBarRenderer : ViewRenderer<Outcoder.UI.Xaml.AppBar, Outcoder.UI.Xaml.Controls.AppBar>
	{
		bool initialized;
		static WeakReference<Page> appBarOwner;

		protected override void OnElementChanged(ElementChangedEventArgs<AppBar> e)
		{
			base.OnElementChanged(e);

			var oldElement = e.OldElement;

			if (oldElement != null)
			{
				DetachAppBar(oldElement);
			}

			if (!initialized)
			{
				initialized = true;

				Page page = GetHostPage();
				page.Disappearing += HandlePageDisappearing;
				page.Appearing += HandlePageAppearing;

				var wpAppBar = new Outcoder.UI.Xaml.Controls.AppBar();

				SetNativeControl(wpAppBar);
			}

			AppBar newAppBar = e.NewElement;
			AttachAppBar(newAppBar);
		}

		void HandlePageDisappearing(object sender, EventArgs e)
		{
			Page ownerPage;
			if (appBarOwner != null && appBarOwner.TryGetTarget(out ownerPage))
			{
				var hostContentPage = GetHostPage();
				if (ownerPage != hostContentPage)
				{
					return;
				}
			}

			HideAppBar();
		}

		void HandlePageAppearing(object sender, EventArgs e)
		{
			Page ownerPage = GetHostPage();
			appBarOwner = new WeakReference<Page>(ownerPage);
			UpdateAppBar();
		}

		void HideAppBar()
		{
			var wpAppBar = Control;

			if (wpAppBar == null)
			{
				return;
			}

			wpAppBar.IsVisible = false;
		}

		void AttachAppBar(AppBar appBar)
		{
			if (appBar == null)
			{
				return;
			}

			DetachAppBar(appBar);

			appBar.ButtonCollectionChanged += HandleButtonsChanged;
			appBar.MenuItemCollectionChanged += HandleMenuItemsChanged;
		}

		void DetachAppBar(AppBar appBar)
		{
			if (appBar == null)
			{
				return;
			}

			appBar.ButtonCollectionChanged -= HandleButtonsChanged;
			appBar.MenuItemCollectionChanged -= HandleMenuItemsChanged;
		}

		void HandleMenuItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
		{
			UpdateAppBar();
		}

		void HandleButtonsChanged(object sender, NotifyCollectionChangedEventArgs e)
		{
			UpdateAppBar();
		}

		Page GetHostPage()
		{
			return GetParentOfType<Page>();
		}

		T GetParentOfType<T>() where T : class
		{
			T page = null;
			Element parent = Element;
			while (page == null)
			{
				parent = parent.Parent;
				if (parent == null)
				{
					break;
				}
				page = parent as T;
			}

			return page;
		}

		public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
		{
			return new SizeRequest(new Size(widthConstraint, 73));
		}

		void UpdateAppBar()
		{
			var wpAppBar = Control;

			if (wpAppBar == null)
			{
				return;
			}

			wpAppBar.Buttons.Clear();
			wpAppBar.MenuItems.Clear();

			var xamAppBar = Element;

			var xamButtons = xamAppBar.Buttons.ToList();
			var xamMenuItems = xamAppBar.MenuItems.ToList();

			if (!xamButtons.Any())
			{
				if (!xamMenuItems.Any())
				{
					wpAppBar.IsVisible = false;
					return;
				}

				wpAppBar.Mode = Microsoft.Phone.Shell.ApplicationBarMode.Minimized;
			}

			wpAppBar.IsVisible = true;

			foreach (var item in xamAppBar.Buttons)
			{
				string text;
				if (!AppBarItemPropertyResolver.TryGetItemText(item, out text))
				{
					throw new Exception("Unable to resolve text for button.");
				}

				var button = new Outcoder.UI.Xaml.Controls.AppBarIconButton();
				button.Text = text;

				string iconUrl;
				Uri iconUri = null;

				if (AppBarItemPropertyResolver.TryGetItemUrl(item, out iconUrl))
				{
					iconUri = new Uri(iconUrl, UriKind.Relative);
				}

				button.IconUri = iconUri;
				IAppBarItem i = item;
				button.Click += (sender, args) => i.PerformTap();
				wpAppBar.Buttons.Add(button);
			}

			foreach (IAppBarItem item in xamAppBar.MenuItems)
			{
				string text;
				if (!AppBarItemPropertyResolver.TryGetItemText(item, out text))
				{
					throw new Exception("Unable to resolve text for button.");
				}

				var menuItem = new Outcoder.UI.Xaml.Controls.AppBarMenuItem();
				menuItem.Text = text;
				/* Menu item icons are not supported on Windows Phone. */
				//menuItem.IconUri = item.IconUri; 
				IAppBarItem i = item;
				menuItem.Click += (sender, args) => i.PerformTap();
				wpAppBar.MenuItems.Add(menuItem);
			}
		}
	}
}
